package cn.genmer.test.security.controller;

import cn.genmer.test.security.common.CommonResult;
import cn.genmer.test.security.model.mongoModel.Fruit;
import cn.genmer.test.security.utils.AliyunAddressUtils;
import cn.genmer.test.security.utils.ThreadPoolSizeUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.lang3.StringUtils;
import org.bson.types.ObjectId;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.web.bind.annotation.*;

import java.util.HashMap;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;

/**
 *  参考文档： https://my.oschina.net/u/3452433/blog/2999501
 */
@RestController("/mongo")
@Api(tags = "MongoDB测试控制器")
public class MongoController {

    private static final String COLLECTION_INFO = "info";
    private static final String COLLECTION_COMPLETE = "complete";
    private static final String COLLECTION_STRUCTURE = "structure";

    @Autowired
    private MongoTemplate mongoTemplate;


    /**
     * 新增文档
     * @param fruit
     * @return
     */
    @PostMapping(value = "/insert")
    @ApiOperation("新增")
    public CommonResult insert(@RequestBody Fruit fruit){
        Fruit insert = mongoTemplate.insert(fruit);
        if (insert == null){
            return CommonResult.error("新增失败");
        }
        return CommonResult.success();
    }

    /**
     * 更新文档
     * @return
     */
    @ApiOperation("更新")
    @PostMapping(value = "/save")
    public CommonResult save(){
        Fruit tmp = mongoTemplate.findOne(Query.query(Criteria.where("id").is("61724f64fb51b1c0458c3f38")), Fruit.class);
        tmp.setName("rush update");
        Fruit save = mongoTemplate.save(tmp);
        if (save == null){
            return CommonResult.error("更新失败");
        }
        return CommonResult.success("更新成功");
    }

    /**
     * 删除文档
     * @param id
     * @return
     */
    @ApiOperation("删除")
    @GetMapping(value = "/delete")
    public CommonResult delete(@RequestParam String id){

        Query query = Query.query(Criteria.where("id").is(new ObjectId(id)));
        Fruit result = mongoTemplate.findOne(query, Fruit.class);
        mongoTemplate.remove(result);

        return CommonResult.success("删除成功");
    }

    /**
     * 查询文档
     * @param id
     * @return
     */
    @ApiOperation("查询")
    @GetMapping(value = "/findOne")
    public CommonResult findOne(@RequestParam String id){

        Query query = Query.query(Criteria.where("id").is(new ObjectId(id)));
        Fruit result = mongoTemplate.findOne(query, Fruit.class);
        if (result == null){
            return CommonResult.error("未查询到记录");
        }
        return CommonResult.success(result);
    }

    /**
     * 拉取阿里云-地址标准化数据
     * @return
     */
    @ApiOperation("拉取阿里云-地址标准化数据 - 线程池")
    @GetMapping(value = "/getAll")
    public CommonResult findAll(){

        // 获取全部记录
        List<JSONObject> list = mongoTemplate.findAll(JSONObject.class, COLLECTION_STRUCTURE);

        // 获取100条记录
//        Query query = new Query();
//        query.skip(11095);
//        query.limit(30);
//        List<JSONObject> list = mongoTemplate.find(query, JSONObject.class, COLLECTION_STRUCTURE);

        ExecutorService executorService = Executors.newFixedThreadPool(ThreadPoolSizeUtil.ioIntesivePoolSize());
        AtomicInteger successCount = new AtomicInteger(0);
        for (JSONObject json: list){
            if (json.get("prov") != null && StringUtils.isNotBlank(json.get("prov").toString())) continue;
            executorService.submit(() -> {
                try {
                    updateMongoData(json, AliyunAddressUtils.API_TYPE_STRUCTUREADDRESS);
                    System.out.println(String.format("运单号为：[%s]的数据已完成解析",json.get("ewbno")));
                    successCount.getAndIncrement();
                    System.out.println(String.format("本次执行已完成更新数量：%d", successCount.get()));
                } catch (Exception e){
                    e.printStackTrace();
                }
            });
        }

        return CommonResult.success();
    }


    /**
     * 拉取阿里云-地址标准化数据
     * @return
     */
    @ApiOperation("拉取阿里云-地址标准化数据 - 数据限制")
    @GetMapping(value = "/getAll2")
    public CommonResult findAll2(){

        // 获取全部记录
        List<JSONObject> list = mongoTemplate.findAll(JSONObject.class, COLLECTION_STRUCTURE);

        // 获取100条记录
//        Query query = new Query();
//        query.skip(8600);
//        List<JSONObject> list = mongoTemplate.find(query, JSONObject.class, COLLECTION_STRUCTURE);

        AtomicInteger successCount = new AtomicInteger(0);
        try {
            for (JSONObject json: list){
                if (json.get("prov") != null && StringUtils.isNotBlank(json.get("prov").toString())) continue;
                if (json.get("city") != null && StringUtils.isNotBlank(json.get("city").toString())) continue;
                if (json.get("district") != null && StringUtils.isNotBlank(json.get("district").toString())) continue;
                // 跑太快了，限制下
                Thread.sleep(50);
                    updateMongoData(json, AliyunAddressUtils.API_TYPE_STRUCTUREADDRESS);
                    System.out.println(String.format("运单号为：[%s]的数据已完成解析",json.get("ewbno")));
                    successCount.getAndIncrement();
                    System.out.println(String.format("已完成更新数量：%d", successCount.get()));
            }
        } catch (Exception e){
            e.printStackTrace();
        }
        return CommonResult.success();
    }
    /**
     * 更新单条Mongo数据
     * @param result
     * @return
     */
    private void updateMongoData(JSONObject result, String type) throws Exception {
        if (result == null){
            throw new Exception("未查询到记录");
        }
        // 与源数据合并
        JSONObject requestResult = getResult(result, type);
        if (requestResult == null){
            return;
        }
        result.putAll(requestResult);
        // 保存
        saveResult(result, type);

    }

    /**
     * 请求接口数据，合并到源数据
     * @param result 要保存的mongo对象
     * @param type 请求接口类型
     * @return
     * @throws Exception
     */
    private synchronized JSONObject getResult(JSONObject result, String type) throws Exception {
        // 获取源记录中需要分析的地址
        String address = result.getString("address");
        if(StringUtils.isBlank(address)){
            throw new Exception("地址为空");
        }

        String response = null;
        String responseResult = null;
        // 调用阿里云AI-地址标准化-根据类型请求获取结果
        // 地址补全
        if (AliyunAddressUtils.API_TYPE_COMPLETEADDRESS.equalsIgnoreCase(type)){
            response = AliyunAddressUtils.completeAddress(address);
            // 结果转化为JSONObject
            JSONObject responseJson = JSON.parseObject(response);
            responseResult = responseJson.getString(AliyunAddressUtils.API_TYPE_COMPLETEADDRESS);
        }
        // 地址结构化
        else if (AliyunAddressUtils.API_TYPE_STRUCTUREADDRESS.equalsIgnoreCase(type)){
            response = AliyunAddressUtils.structureAddress(address);
            // 结果转化为JSONObject
            JSONObject responseJson = JSON.parseObject(response);
            responseResult = responseJson.getString(AliyunAddressUtils.API_TYPE_STRUCTUREADDRESS);
        } else {
            throw new Exception("请选择正确的请求接口类型");
        }


//        if (StringUtils.isBlank(responseResult))   throw new Exception(String.format("更新失败, 请求结果为空: 请求地址为 %s", address));
        if (StringUtils.isBlank(responseResult)) {
            System.err.println(String.format("更新失败, 请求结果为空: 请求地址为 %s", address));
            return null;
        };
        return  JSON.parseObject(transJson(responseResult));
    }

    /**
     * 保存结果
     * @param result 要保存的mongo对象
     * @param type 请求接口类型
     * @throws Exception
     */
    private void saveResult(JSONObject result, String type) throws Exception {
        // 保存
        JSONObject save = null;

        if (AliyunAddressUtils.API_TYPE_COMPLETEADDRESS.equalsIgnoreCase(type)){
            save = mongoTemplate.save(result,COLLECTION_COMPLETE);
        } else if (AliyunAddressUtils.API_TYPE_STRUCTUREADDRESS.equalsIgnoreCase(type)){
            save = mongoTemplate.save(result,COLLECTION_STRUCTURE);
        } else {
            throw new Exception("请选择正确的请求接口类型");
        }
        if (save == null){
            throw new Exception("更新失败");
        }
    }

    /**
     * 阿里云地址标准化结果转化为JSON格式 - 结果示例： prov=浙江省\tcity=宁波市\tdistrict=北仑区\ttown=新碶街道\troad=太河北路\troadno=218号
     * @param str
     * @return
     */
    private static String transJson(String str){
        if (StringUtils.isBlank(str)) return null;
        String[] split = str.split("\\t");
        HashMap<String, String> map = new HashMap<>();
        for (String tmp: split){
            String[] keyValue = tmp.trim().split("=");
            // 避免 = 后无值，数组越界
            if (!(keyValue.length < 0)){
                if (keyValue.length == 1){
                    keyValue[1] = "";
                }
            } else {
                continue;
            }
            map.put(keyValue[0],keyValue[1] == null ? "" : keyValue[1]);
        }
        return JSON.toJSONString(map);
    }

    public static void main(String[] args) {
        System.out.println(transJson("prov=浙江省\tcity=宁波市\tdistrict=北仑区\ttown=新碶街道\troad=太河北路\troadno=218号"));
    }
}
